/********************************************************/
/*	Copyright (C) 2016 Gong Li Bin			*/
/*	Project:	GlbCloud			*/
/*	Author:		gong_libin			*/
/*	Date:		2012_09_17			*/
/*	File:		MrPro.cpp			*/
/********************************************************/

#include "MrPro.h"

CMrPro::CMrPro()
{
	m_puszBody = NULL;
	memset(m_uszExHead, '\0', MR_PRO_EXPA);
	memset(&m_stHead, '\0', sizeof(MRPROHEAD_S));
}

CMrPro::~CMrPro()
{
}

UCHAR CMrPro::MrProGetFlag()
{
	return m_stHead.m_ucFlag;
}

UCHAR CMrPro::MrProGetReal()
{
	return m_stHead.m_ucReal;
}

UCHAR CMrPro::MrProGetType()
{
	return m_stHead.m_ucType;
}

UCHAR CMrPro::MrProGetVerb()
{
	return m_stHead.m_ucVerb;
}

UCHAR CMrPro::MrProGetAttr()
{
	return m_stHead.m_ucAttr;
}

int CMrPro::MrProGetLength()
{
	return m_stHead.m_iLength;
}

USHORT CMrPro::MrProGetTotal()
{
	return m_stHead.m_usTotal;
}

UCHAR CMrPro::MrProGetExpand()
{
	return m_stHead.m_ucExpand;
}

UCHAR CMrPro::MrProGetResult()
{
	return m_stHead.m_ucResult;
}

UCHAR CMrPro::MrProGetVersion()
{
	return m_stHead.m_ucVersion;
}

UCHAR CMrPro::MrProGetProtocol()
{
	return m_stHead.m_ucProtocol;
}

UCHAR CMrPro::MrProGetResponse()
{
	return m_stHead.m_ucResponse;
}

UCHAR* CMrPro::MrProGetBody()
{
	return m_puszBody;
}

UCHAR* CMrPro::MrProGetExHead()
{
	return m_uszExHead;
}

MRPROHEAD_S* CMrPro::MrProGetHead()
{
	return &m_stHead;
}

void CMrPro::MrProPutFlag(UCHAR ucFlag)
{
	m_stHead.m_ucFlag = ucFlag;

	return;
}

void CMrPro::MrProPutReal(UCHAR ucReal)
{
	m_stHead.m_ucReal = ucReal;

	return;
}

void CMrPro::MrProPutType(UCHAR ucType)
{
	m_stHead.m_ucType = ucType;

	return;
}

void CMrPro::MrProPutVerb(UCHAR ucVerb)
{
	m_stHead.m_ucVerb = ucVerb;

	return;
}

void CMrPro::MrProPutAttr(UCHAR ucAttr)
{
	m_stHead.m_ucAttr = ucAttr;

	return;
}

void CMrPro::MrProPutLength(int iLength)
{
	m_stHead.m_iLength = iLength;

	return;
}

void CMrPro::MrProPutTotal(USHORT usTotal)
{
	m_stHead.m_usTotal = usTotal;

	return;
}

void CMrPro::MrProPutExpand(UCHAR ucExpand)
{
	m_stHead.m_ucExpand = ucExpand;

	return;
}

void CMrPro::MrProPutResult(UCHAR ucResult)
{
	m_stHead.m_ucResult = ucResult;

	return;
}

void CMrPro::MrProPutVersion(UCHAR ucVersion)
{
	m_stHead.m_ucVersion = ucVersion;

	return;
}

void CMrPro::MrProPutProtocol(UCHAR ucProtocol)
{
	m_stHead.m_ucProtocol = ucProtocol;

	return;
}

void CMrPro::MrProPutResponse(UCHAR ucResponse)
{
	m_stHead.m_ucResponse = ucResponse;

	return;
}

void CMrPro::MrProPutBody(UCHAR* puszBody)
{
	m_puszBody = puszBody;

	return;
}

void CMrPro::MrProPutExHead(UCHAR* puszExHead)
{
	memcpy(m_uszExHead, puszExHead, MR_PRO_EXPA);

	return;
}

void CMrPro::MrProPutHead(MRPROHEAD_S* pstHead)
{
	memcpy(&m_stHead, pstHead, sizeof(MRPROHEAD_S));

	return;
}

void CMrPro::MrProReset()
{
	memset(&m_stHead, '\0', sizeof(MRPROHEAD_S));
	m_puszBody = NULL;

	return;
}

void CMrPro::MrProDisplay()
{
	MR_PRINT("Flag: 0x%02x\t", m_stHead.m_ucFlag);
	MR_PRINT("Version: 0x%02x\t", m_stHead.m_ucVersion);
	MR_PRINT("Protocol: 0x%02x\t", m_stHead.m_ucProtocol);
	MR_PRINT("Real: 0x%02x\t", m_stHead.m_ucReal);
	MR_PRINT("Response: 0x%02x\t", m_stHead.m_ucResponse);
	MR_PRINT("Expand: 0x%02x\n", m_stHead.m_ucExpand);
	MR_PRINT("Type: 0x%02x\t", m_stHead.m_ucType);
	MR_PRINT("Verb: 0x%02x\t", m_stHead.m_ucVerb);
	MR_PRINT("Attr: 0x%02x\t", m_stHead.m_ucAttr);
	MR_PRINT("Result: 0x%02x\t", m_stHead.m_ucResult);
	MR_PRINT("Total: %d\t", m_stHead.m_usTotal);
	MR_PRINT("Length: %d\t", m_stHead.m_iLength);

	if (MR_PRO_1 == m_stHead.m_ucExpand) {
		MR_PRINT("ExHead: %p\t", m_uszExHead);
	}
	else {
		MR_PRINT("ExHead: NULL\t");
	}

	if (NULL != m_puszBody) {
		MR_PRINT("Body: %p\n", m_puszBody);
	}
	else {
		MR_PRINT("Body: NULL\n");
	}

	return;
}

void CMrPro::MrProClone(CMrPro& rCPro)
{
	memcpy(&m_stHead, rCPro.MrProGetHead(), sizeof(MRPROHEAD_S));
	memcpy(&m_uszExHead, rCPro.MrProGetExHead(), MR_PRO_EXPA);
	m_puszBody = rCPro.MrProGetBody();

	return;
}

void CMrPro::MrProInduce(MRPROHEAD_S* pstHead)
{
	memcpy(&m_stHead, pstHead, sizeof(MRPROHEAD_S));

	return;
}

void CMrPro::MrProParse(UCHAR* puszPacket, int iLength)
{
	UCHAR* puszCur = puszPacket;

	if (MR_PRO_FLAG == (m_stHead.m_ucFlag = *puszCur)) {
		puszCur += sizeof(UCHAR);
	}
	else {
		return;
	}

	m_stHead.m_ucVersion = *puszCur >> 4;
	m_stHead.m_ucProtocol = (*puszCur & 0x0f) >> 3;
	m_stHead.m_ucReal = (*puszCur & 0x07) >> 2;
	m_stHead.m_ucResponse = (*puszCur & 0x03) >> 1;
	m_stHead.m_ucExpand = *puszCur & 0x01;
	puszCur += sizeof(UCHAR);

	m_stHead.m_ucType = *puszCur;
	puszCur += sizeof(UCHAR);

	m_stHead.m_ucVerb = *puszCur;
	puszCur += sizeof(UCHAR);

	m_stHead.m_ucAttr = *puszCur;
	puszCur += sizeof(UCHAR);

	m_stHead.m_ucResult = *puszCur;
	puszCur += sizeof(UCHAR);

	m_stHead.m_usTotal = ntohs(*(USHORT*)puszCur);
	puszCur += sizeof(USHORT);

	m_stHead.m_iLength = ntohl(*(int*)puszCur);
	puszCur += sizeof(int);

	if (MR_PRO_1 == m_stHead.m_ucExpand) {
		memcpy(m_uszExHead, puszCur, MR_PRO_EXPA);
		puszCur += MR_PRO_EXPA;
		if (iLength > MR_PRO_HEAD + MR_PRO_EXPA) {
			m_puszBody = puszCur;
		}
	}
	else {
		if (iLength > MR_PRO_HEAD) {
			m_puszBody = puszCur;
		}
	}

	return;
}

void CMrPro::MrProCreate(UCHAR* puszPacket, int iLength)
{
	UCHAR* puszCur = puszPacket;

	*puszCur = MR_PRO_FLAG;
	puszCur += sizeof(UCHAR);

	*puszCur = m_stHead.m_ucVersion << 4;
	*puszCur |= m_stHead.m_ucProtocol << 3;
	*puszCur |= m_stHead.m_ucReal << 2;
	*puszCur |= m_stHead.m_ucResponse << 1;
	*puszCur |= m_stHead.m_ucExpand;
	puszCur += sizeof(UCHAR);

	*puszCur = m_stHead.m_ucType;
	puszCur += sizeof(UCHAR);

	*puszCur = m_stHead.m_ucVerb;
	puszCur += sizeof(UCHAR);

	*puszCur = m_stHead.m_ucAttr;
	puszCur += sizeof(UCHAR);

	*puszCur = m_stHead.m_ucResult;
	puszCur += sizeof(UCHAR);

	*(USHORT*)puszCur = htons(m_stHead.m_usTotal);
	puszCur += sizeof(USHORT);

	*(int*)puszCur = htonl(m_stHead.m_iLength);
	puszCur += sizeof(int);

	if (MR_PRO_1 == m_stHead.m_ucExpand) {
		memcpy(puszCur, m_uszExHead, MR_PRO_EXPA);
		if (NULL != m_puszBody) {
			memcpy(puszCur + MR_PRO_EXPA, m_puszBody, m_stHead.m_iLength < iLength ? m_stHead.m_iLength : iLength);
		}
	}
	else {
		if (NULL != m_puszBody) {
			memcpy(puszCur, m_puszBody, m_stHead.m_iLength < iLength ? m_stHead.m_iLength : iLength);
		}
	}

	return;
}

void CMrPro::MrProRequest(UCHAR* puszPacket)
{
	MRPROHEAD_S stHead = {
		MR_PRO_FLAG,
		MR_PRO_1,
		MR_PRO_CTRL,
		MR_PRO_0,
		MR_PRO_Y,
		MR_PRO_0,
		MR_PRO_0,
		MR_PRO_0,
		MR_PRO_0,
		MR_PRO_0,
		MR_PRO_0,
		MR_PRO_0,
	};

	MrProInduce(&stHead);
	MrProCreate(puszPacket, MR_PRO_HEAD);

	return;
}

void CMrPro::MrProResponse(UCHAR* puszPacket)
{
	MRPROHEAD_S stHead = {
		MR_PRO_FLAG,
		MR_PRO_1,
		MR_PRO_CTRL,
		MR_PRO_0,
		MR_PRO_N,
		MR_PRO_0,
		MR_PRO_0,
		MR_PRO_0,
		MR_PRO_0,
		MR_DEF_SUCC,
		MR_PRO_0,
		MR_PRO_0,
	};

	MrProInduce(&stHead);
	MrProCreate(puszPacket, MR_PRO_HEAD);

	return;
}

void MrProKvFree(MRPROKV_S** ppstKv, USHORT usTotal)
{
	USHORT usCount = 0;

	for (usCount = 0; usCount < usTotal; usCount ++) {
		if (NULL != (*ppstKv + usCount)->m_puszValue) {
			MrFree((void**)&(*ppstKv + usCount)->m_puszValue);
		}
	}
	MrFree((void**)ppstKv);

	return;
}

void MrProKvDisplay(MRPROKV_S* pstKv, USHORT usTotal)
{
	USHORT usCount = 0;
	char* pszValue = NULL;

	while (usCount < usTotal) {
		if ('\0' != (pstKv + usCount)->m_ucKey) {
			if (NULL != (pszValue = (char*)MrMalloc(sizeof(char) * (pstKv + usCount)->m_iLength + 1))) {
				memcpy(pszValue, (pstKv + usCount)->m_puszValue, (pstKv + usCount)->m_iLength);
				MR_PRINT("Key[%d] -> Len[%d] -> Val[%s]\n", (pstKv + usCount)->m_ucKey, (pstKv + usCount)->m_iLength, pszValue);
				MrFree((void**)&pszValue);
			}
		}
		else {
			break;
		}
		usCount += 1;
	}

	return;
}

MRPROKV_S* MrProKvMalloc(USHORT usTotal, int iSize)
{
	USHORT usCount = 0;
	MRPROKV_S* pstKv = NULL;

	if (NULL != (pstKv = (MRPROKV_S*)MrMalloc(sizeof(MRPROKV_S) * usTotal))) {
		for (usCount = 0; usCount < usTotal; usCount ++) {
			if (NULL == ((pstKv + usCount)->m_puszValue = (UCHAR*)MrMalloc(sizeof(UCHAR) * iSize))) {
				MR_ERROR("%s\n", strerror(errno));
				MrProKvFree(&pstKv, usTotal);
				break;
			}
		}
	}

	return pstKv;
}

void MrProKvReset(MRPROKV_S* pstKv, USHORT usTotal, int iSize)
{
	USHORT usCount = 0;

	for (usCount = 0; usCount < usTotal; usCount ++) {
		if (NULL != (pstKv + usCount)->m_puszValue) {
			(pstKv + usCount)->m_ucKey = 0;
			(pstKv + usCount)->m_iLength = 0;
			memset((pstKv + usCount)->m_puszValue, '\0', iSize);
		}
	}

	return;
}

int MrProKvInput(MRPROKV_S* pstKv, USHORT usTotal, UCHAR* puszPacket, int iLength)
{
	USHORT usCount = 0;
	UCHAR* puszCur = puszPacket;

	while ((int)(puszCur - puszPacket) < iLength) {
		if (usCount < usTotal) {
			(pstKv + usCount)->m_ucKey = *puszCur;
			(pstKv + usCount)->m_iLength = ntohl(*(int*)(puszCur + sizeof(UCHAR)));
			(pstKv + usCount)->m_puszValue = puszCur + MR_PRO_KEYLEN;
		}
		else {
			return MR_FAILURE;
		}
		puszCur += MR_PRO_KEYLEN + (pstKv + usCount)->m_iLength;
		usCount += 1;
	}

	return MR_SUCCESS;
}

int MrProKvOutput(MRPROKV_S* pstKv, USHORT usTotal, UCHAR* puszPacket, int iLength)
{
	USHORT usCount = 0;
	UCHAR* puszCur = puszPacket;

	while ((int)(puszCur - puszPacket) < iLength) {
		if (usCount < usTotal) {
			if ('\0' != (pstKv + usCount)->m_ucKey) {
				*puszCur = (pstKv + usCount)->m_ucKey;
				*(int*)(puszCur + sizeof(UCHAR)) = htonl((pstKv + usCount)->m_iLength);
				memcpy(puszCur + MR_PRO_KEYLEN, (pstKv + usCount)->m_puszValue, (pstKv + usCount)->m_iLength);
				puszCur += MR_PRO_KEYLEN + (pstKv + usCount)->m_iLength;
			}
			else {
				break;
			}
		}
		else {
			break;
		}
		usCount += 1;
	}

	return (int)(puszCur - puszPacket);
}

void MrProWKvSet(MRPROWKV_S* pstWKv, UCHAR* puszPacket)
{
	pstWKv->m_usKey = ntohs(*(USHORT*)puszPacket);
	pstWKv->m_puszValue = puszPacket + sizeof(USHORT);

	return;
}

void MrProWKlvInput(MRPROWKLV_S* pstWKlv, UCHAR* puszPacket)
{
	pstWKlv->m_usKey = ntohs(*(USHORT*)puszPacket);
	pstWKlv->m_puszValue = puszPacket + MR_PRO_WKLV;
	pstWKlv->m_iLength = ntohl(*(int*)(puszPacket + sizeof(USHORT)));

	return;
}

void MrProWKlvOutPut(MRPROWKLV_S* pstWKlv, UCHAR* puszPacket)
{
	*(USHORT*)puszPacket = htons(pstWKlv->m_usKey);
	*(int*)(puszPacket + sizeof(USHORT)) = htonl(pstWKlv->m_iLength);
	memcpy(puszPacket + MR_PRO_WKLV, pstWKlv->m_puszValue, pstWKlv->m_iLength);

	return;
}
